package com.jlpay.open.jlpay.sdk.java.sign;

import com.jlpay.open.jlpay.sdk.java.exception.KeyInitializationException;
import com.jlpay.open.jlpay.sdk.java.exception.SignVerifyException;
import com.jlpay.open.jlpay.sdk.java.http.JlpayHttpHeaders;
import com.jlpay.open.jlpay.sdk.java.utils.gm.BcecUtils;
import com.jlpay.open.jlpay.sdk.java.utils.gm.Sm2Utils;
import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Security;
import java.security.spec.InvalidKeySpecException;
import java.util.Base64;

/**
 * @author zhaomeixia
 * @since 2024/2/20
 */
public class SignVerifier {

    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    /**
     * 机构私钥
     */
    private final BCECPrivateKey orgPrivateKey;
    /**
     * 嘉联公钥
     */
    private final BCECPublicKey jlpayPublicKey;

    public SignVerifier(String orgPriKey, String jlpayPubKey) {
        try {
            byte[] priKeyData = BcecUtils.convertEcPrivateKeyPemToPkcs8(orgPriKey);
            this.orgPrivateKey = BcecUtils.convertPkcs8ToEcPrivateKey(priKeyData);

            byte[] pubKeyData = BcecUtils.convertEcPublicKeyPemToX509(jlpayPubKey);
            this.jlpayPublicKey = BcecUtils.convertX509ToEcPublicKey(pubKeyData);
        } catch (IOException | NoSuchAlgorithmException | NoSuchProviderException | InvalidKeySpecException e) {
            throw new KeyInitializationException("密钥初始化异常", e);
        }
    }

    public SignVerifier(String jlpayPubKey) {
        try {
            byte[] pubKeyData = BcecUtils.convertEcPublicKeyPemToX509(jlpayPubKey);
            this.jlpayPublicKey = BcecUtils.convertX509ToEcPublicKey(pubKeyData);
        } catch (IOException | NoSuchAlgorithmException | NoSuchProviderException | InvalidKeySpecException e) {
            throw new KeyInitializationException("密钥初始化异常", e);
        }
        orgPrivateKey = null;
    }


    public SignVerifier(BCECPublicKey jlpayPublicKey) {
        this.jlpayPublicKey = jlpayPublicKey;
        orgPrivateKey = null;
    }

    public SignVerifier(BCECPrivateKey orgPrivateKey, BCECPublicKey jlpayPublicKey) {
        this.orgPrivateKey = orgPrivateKey;
        this.jlpayPublicKey = jlpayPublicKey;
    }

    public String sign(String data, String algorithm) {
        try {
            if (!JlpayHttpHeaders.V5.ALG_SM3_WITH_SM2_WITH_DER.equals(algorithm)) {
                throw new SignVerifyException("unsupported algorithm: " + algorithm);
            }
            byte[] result = Sm2Utils.sign(orgPrivateKey, data.getBytes());
            return new String(Base64.getEncoder().encode(result));
        } catch (NoSuchAlgorithmException | NoSuchProviderException | CryptoException e) {
            throw new SignVerifyException("sign failed", e);
        }
    }

    public boolean verify(String data, String sign, String algorithm) {
        if (!JlpayHttpHeaders.V5.ALG_SM3_WITH_SM2_WITH_DER.equals(algorithm)) {
            throw new SignVerifyException("unsupported algorithm: " + algorithm);
        }
        return Sm2Utils.verify(jlpayPublicKey,
                data.getBytes(StandardCharsets.UTF_8),
                Base64.getDecoder().decode(sign));
    }
}
